#include "MySqlConnPool.h"
#include <fstream>
#include <map>
#include "log/Log.h"
#include "json11/json11.hpp"
#include "utils/StringUtil.h"

namespace db
{

MySqlConnPool::MySqlConnPool()
{
}

MySqlConnPool::~MySqlConnPool()
{

}

bool MySqlConnPool::init(const std::string& strFile)
{
    utils::LockGuard<utils::Mutex> lock(m_mutex);
    if (!parseFromJson(strFile))
    {
        return false;
    }

    for (int i = 0; i < m_nMaxSize; i++)
    {
        MySqlConn* conn = new MySqlConn();
        if (!conn->connect(*m_ptrConf))
        {
            delete conn;
            continue;
        }
        m_listConns.emplace_back(conn);
    }
    return true;
}

MySqlConn::ptr MySqlConnPool::getConn()
{
    utils::LockGuard<utils::Mutex> lock(m_mutex);
    MySqlConn* conn = nullptr;
    while(!m_listConns.empty())
    {
        conn = m_listConns.front();
        m_listConns.pop_front();
        if (conn->isConnected())
        {
            break;
        }
        conn = nullptr;
    }

    if (nullptr == conn)
    {
        conn = new MySqlConn;
        if (nullptr == m_ptrConf || !conn->connect(*m_ptrConf))
        {
            delete conn;
            return MySqlConn::ptr();
        }
    }
    return MySqlConn::ptr(conn, [this](MySqlConn* conn){
            if (m_listConns.size() > m_nMaxSize) 
            {
                delete conn; 
                return;
            }
            m_listConns.emplace_back(conn);
        });
}

bool MySqlConnPool::parseFromJson(const std::string& strFile)
{
    std::ifstream ifs(strFile);
    if (!(ifs.is_open()))
    {
        SYS_ERROR() << "mysql pool open config error, file: " << strFile;
        return false;
    }

    std::string strJson((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); 

    std::string err;
    json11::Json json =  json11::Json::parse(strJson, err, json11::STANDARD);
    if (!err.empty())
    {
        SYS_ERROR() << "mysql connect pool parse config error, json: " << strJson;
        return false;
    }

    json11::Json pool = json["pool"];
    m_nMaxSize = pool["max_size"].int_value();
    m_ptrConf = std::make_shared<MySqlConf>();
    json11::Json mysql= pool["mysql"];
    if (!m_ptrConf->parseFromJson(mysql.dump()))
    {
        SYS_ERROR() << "mysql config error, json: " << mysql.dump();
        return false;
    }
    return true;
}

    
} // namespace db
